package dsk.demo.product.controller.automarket;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import dsk.demo.common.utils.StreamUtils;
import dsk.demo.product.config.TonghuashunJob;
import dsk.demo.product.dao.GWeekPriceDao;
import dsk.demo.product.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@RestController
public class TestController {

    private static String baseFilePath = "D:\\Program Files\\HGAME\\萝莉美图";

    @Resource(name = "MyExecutor")
    private ThreadPoolTaskExecutor myExecutor;

    @Autowired
    private GWeekPriceDao weekPriceDao;

    @PostMapping("test")
    public String getImage(@RequestBody String baseUrl) {
//        System.out.println("开始爬取 :" + baseUrl);
//        String content = HttpUtil.createGet(baseUrl)
//                .execute().body();
//        Document doc = Jsoup.parse(content);

        Document doc = Jsoup.parse(baseUrl);
        String title = doc.head().getElementsByTag("title").get(0).ownText();
        Pattern p = Pattern.compile("\\|.+$");
        Matcher matcher = p.matcher(title);
        String s = matcher.replaceAll("").trim();
        title = s;
        Element body = doc.body();
        System.out.println(body.getElementsByClass("att_img").size());
        for (Element att_img : body.getElementsByClass("att_img")) {
            String imageUrl = att_img.getElementsByTag("img").get(0).attr("data-original");
            String finalTitle = title;
            myExecutor.execute(() -> {
                try {
                    System.out.println(finalTitle + ": " + imageUrl);
                    getAndDownloadImage(imageUrl, baseFilePath + "\\" + finalTitle);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }

        System.out.println("爬取完成 :" + baseUrl);

        return "成功";
    }


    public String getAndDownloadImage(String url, String filePath) throws IOException {
        HttpResponse response = HttpUtil.createGet(url)
                .timeout(1000 * 60 * 10)
                .execute();
        System.out.println("请求成功");
        File dir = new File(filePath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File file = response.completeFileNameFromHeader(dir);
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        fileOutputStream.write(response.bodyBytes());
        fileOutputStream.flush();
        fileOutputStream.close();
        response.close();
        return file.getName();
    }

    public static Long idIndex = 400l;

    // 处理分类数据
    public static Map<String, List<Category>> getCategoryList() {

        String s = FileUtil.readString(new File("C:\\Users\\戴世坤\\Desktop\\分类数据.html"), Charset.forName("utf-8"));
        Document doc = Jsoup.parse(s);
        List<Category> list = new ArrayList<>();

        Element menu = doc.getElementsByClass("wd-sub-menu").get(0);
        dealNode(list, menu, 0l);


        Map<Long, Category> categoryMap = StreamUtils.toMap(list, Category::getId, Function.identity());

        for (Category category : list) {
            getCategoryList(categoryMap, category);
        }
        return StreamUtils.groupByKey(list, Category::getName);
//        System.out.println(JSONUtil.toJsonStr(list));
//        CsvWriter writer = CsvUtil.getWriter("C:\\Users\\戴世坤\\Desktop\\新建文件夹\\新全分类数据.csv", Charset.forName("utf-8"));
//        writer.writeBeans(list);
    }

    private static void getCategoryList(Map<Long, Category> categoryMap, Category category) {
        if (category.getParentId().compareTo(0l) == 0) {
            category.setCategoryList(category.getName());
        } else {
            Category parent = categoryMap.get(category.getParentId());
            if (StrUtil.isNotBlank(parent.getCategoryList())) {
                category.setCategoryList(parent.getCategoryList() + " > " + category.getName());
            } else {
                getCategoryList(categoryMap, parent);
            }
        }
    }

    private static void dealNode(List<Category> list, Element menu, Long parentId) {
        for (Element child : menu.children()) {
            // 遍历创建节点
            Elements children = child.children();
            Element node = children.get(0);
            Category build = Category.builder()
                    .id(idIndex++)
                    .parentId(parentId)
                    .name(node.ownText())
                    .slug(node.ownText().trim().toLowerCase().replaceAll(" ", "-"))
                    .build();
            list.add(build);
            if (children.size() == 2) {
                Element childE = children.get(1);
                dealNode(list, childE, build.getId());
            }
        }
    }


    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Category {
        private Long id;
        private Long parentId;
        private Category parent;
        private String name;
        private String slug;
        // 分类层级
        private String categoryList;
        private String categoryUrl;
        private List<Category> children;
    }

    // 爬取一个产品的数据
    public static void dealProduct(String url) {
        String s = HttpUtil.get(url);
        Document doc = Jsoup.parse(s);
        String productTitle = "";
        for (Element elementsByClass : doc.getElementsByClass("entry-summary")) {
            for (Element product_title : elementsByClass.getElementsByClass("product_title")) {
                productTitle = product_title.ownText();
                System.out.println("正在爬取---" + productTitle);
            }
        }

        String sku = productTitle;
        for (Element skuE : doc.getElementsByClass("sku")) {
            if ("N/A".equals(skuE.ownText()) || StrUtil.isBlank(skuE.ownText())) {
                sku = productTitle;
            } else {
                sku = skuE.ownText();
            }
        }
        System.out.println("sku---" + sku);
        Map<String, List<Category>> categoryList = getCategoryList();
        Set<String> categoryListSet = new HashSet<>();
        for (Element posted_in : doc.getElementsByClass("posted_in")) {
            for (Element a : posted_in.getElementsByTag("a")) {
                System.out.println("产品的分类:---" + a.ownText());
                List<Category> categories = categoryList.get(a.ownText().trim());
                if (CollectionUtil.isNotEmpty(categories)) {
                    categoryListSet.addAll(StreamUtils.toList(categories, Category::getCategoryList));
                }
            }
        }

        Set<String> imageSet = new HashSet<>();
        String firstImg = "";
        for (Element content : doc.getElementsByClass("product-image-summary-wrap")) {
            for (Element elementsByClass : content.getElementsByClass("wd-carousel-wrap")) {
                for (Element img : elementsByClass.getElementsByTag("a")) {
                    if (StrUtil.isBlank(firstImg)) {
                        firstImg = img.attr("href");
                    }
                    imageSet.add(img.attr("href"));
                }
            }
        }


        // 获取产品ID
        Long id = 0l;
        for (Element elementsByClass : doc.getElementsByClass("single-product-page")) {
            try {
                String idValue = elementsByClass.attr("id");
                String[] split = idValue.split("-");
                String idStr = split[split.length - 1];
                id = Long.parseLong(idStr);
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("获取ID 报错:[{}]");
            }
        }
        String rPrice = "0";
        String sPrice = "0";
        // 产品价格
        for (Element content : doc.getElementsByClass("product-image-summary")) {
            Elements bdi = content.getElementsByTag("bdi");
            if (bdi.size() == 2) {
                rPrice = bdi.get(0).ownText(); // 正常价格
                sPrice = bdi.get(1).ownText(); // 优惠价格
            } else {
                rPrice = bdi.get(0).ownText(); // 正常价格
            }
        }

        String type = "simple";
        String attrName = "";
        List<String> attrList = new ArrayList<>();

        // 如果有的话统一取第一选择框
        for (Element content : doc.getElementsByClass("product-image-summary")) {
            Elements label = content.getElementsByTag("label");
            if (CollectionUtil.isEmpty(label)) {
                // 单体产品 不用 管属性
                break;
            }
            for (Element select : content.getElementsByTag("select")) {
                type = "variable";
                attrName = label.first().ownText();
                for (Element option : select.getElementsByTag("option")) {
                    if ("Choose an option".equals(option.ownText())) {
                        continue;
                    }
                    // 生成多行记录, parent 是父ID
                    System.out.println("可变量值:--" + option.ownText());
                    attrList.add(option.ownText());
                }
                break;
            }
        }
        List<Map<String, String>> attrSimpList = new ArrayList<>();
        // 第二属性的值取
        for (Element elementsByClass : doc.getElementsByClass("woocommerce-product-attributes-item")) {
            Map<String, String> attrMap = new HashMap<>();
            for (Element byClass : elementsByClass.getElementsByClass("wd-attr-name-label")) {
                attrMap.put("name", byClass.ownText());
            }
            for (Element byClass : elementsByClass.getElementsByClass("woocommerce-product-attributes-item__value")) {
                attrMap.put("value", byClass.ownText());
            }
            attrSimpList.add(attrMap);
        }

        List<Product> productList = new ArrayList<>();
        Product mainProduct = Product.builder()
                .id(id)
                .Name(productTitle)
                .Type(type)
                .SKU(sku)
                .Images(CollectionUtil.join(imageSet, ", "))
                .Categories(CollectionUtil.join(categoryListSet, ", "))
                .Attribute1Global(1)
                .Attribute1Visible(1)
                .Attribute1Value(CollectionUtil.join(attrList, ","))
                .Attribute1Name(attrName)
                .Attribute2Global(0)
                .Attribute2Visible(1)
                .Attribute2Value(attrSimpList.size() >= 1 ? attrSimpList.get(0).get("value") : null)
                .Attribute2Name(attrSimpList.size() >= 1 ? attrSimpList.get(0).get("name") : null)
                .Attribute3Global(0)
                .Attribute3Visible(1)
                .Attribute3Value(attrSimpList.size() >= 2 ? attrSimpList.get(1).get("value") : null)
                .Attribute3Name(attrSimpList.size() >= 2 ? attrSimpList.get(1).get("name") : null)
                .Stock(100)
                .RegularPrice(rPrice)
                .SalePrice(sPrice)
                .AllowCustomerReviews(1)
                .TaxStatus("taxable")
                .VisibilityInCatalog("visible")
                .IsFeatured(0)
                .Published(1)
                .InStock(1)
                .BackordersAllowed(0)
                .SoldIndividually(0)
                .build();
        productList.add(mainProduct);
        if ("variable".equals(mainProduct.getType())) {
            for (String attr : attrList) {
                Product product = BeanUtil.copyProperties(mainProduct, Product.class);
                product.setId(null);
                product.setImages(firstImg);
                product.setName(mainProduct.getName() + "-" + attr);
                product.setSKU(mainProduct.getSKU() + "-" + attr);
                product.setAttribute1Value(attr);
                product.setParent("id:" + mainProduct.getId());
                product.setType("variation");
                productList.add(product);
            }
        }
        if (CollectionUtil.isNotEmpty(productList)) {

            // 只新增数据
            try {
                lock.lock();
                writer.write(productList, false);
                writer.flush();
            } catch (Exception e) {

            } finally {
                if (lock.isLocked()) {
                    lock.unlock();
                }
            }
        }

    }

    @Builder
    @AllArgsConstructor
    @Data
    @NoArgsConstructor
    public static class Product {
        private Long id;
        private String Type;
        private String SKU;
        private String Name;
        private Integer Published;
        private Integer IsFeatured;
        private String VisibilityInCatalog;
        private Integer ShortDescription;
        private Integer Description;
        private String DateSalePriceStarts;
        private String DateSalePriceEnds;
        private String TaxStatus;
        private String TaxClass;
        private Integer InStock;
        private Integer Stock;
        private Integer LowStockAmount;
        private Integer BackordersAllowed;
        private Integer SoldIndividually;
        private String Weight;
        private String Length;
        private String Width;
        private String Height;
        private Integer AllowCustomerReviews;
        private String PurchaseNote;
        private String SalePrice;
        private String RegularPrice;
        private String Categories;
        private String Tags;
        private String ShippingClass;
        private String Images;
        private String DownloadLimit;
        private String Download;
        private String expiryDays;
        private String Parent;
        private String GroupedProducts;
        private String Upsells;
        private String CrossSells;
        private String ExternalURL;
        private String ButtonText;
        private String Position;
        private String SwatchesAttributes;
        private String Attribute1Name;
        private String Attribute1Value;
        private Integer Attribute1Visible;
        private Integer Attribute1Global;
        private String Attribute2Name;
        private String Attribute2Value;
        private Integer Attribute2Visible;
        private Integer Attribute2Global;
        private String Attribute3Name;
        private String Attribute3Value;
        private Integer Attribute3Visible;
        private Integer Attribute3Global;

    }

    private static ThreadPoolTaskExecutor executor;
    private static ReentrantLock lock = new ReentrantLock();
    private static ExcelWriter writer;

    static {
        File file = new File("C:\\Users\\戴世坤\\Desktop\\新建文件夹\\新全产品数据.xls");
        writer = ExcelUtil.getWriter(file);
        executor = new ThreadPoolTaskExecutor();
        int threadNumber = 2;
        // 设置核心线程数
        executor.setCorePoolSize(threadNumber);
        // 设置线程队列大小
        executor.setQueueCapacity(threadNumber * 20);
        // 设置线程最大线程数量
        executor.setMaxPoolSize(threadNumber * 2);
        // 设置最大线程空闲时间,达到最大空闲时间则自动销毁
        executor.setKeepAliveSeconds(60);
        // 设置线程池名称前缀
        executor.setThreadNamePrefix("MyExecutor");

        /*
         * rejection-policy：当pool已经达到max size的时候，如何处理新任务
         * CALLER_RUNS：不在新线程中执行任务，而是有调用者所在的线程来执行
         */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 初始化
        executor.initialize();
    }
//
//    public static void main(String[] args) {
//        String s = FileUtil.readString(new File("C:\\Users\\戴世坤\\Desktop\\分类数据.html"), Charset.forName("utf-8"));
//        Document doc = Jsoup.parse(s);
//
//        Element menu = doc.getElementsByClass("wd-sub-menu").get(0);
//        Elements categoryUrls = menu.getElementsByTag("a");
//        Map<String, String> imageMap = new HashMap<>();
//        for (Element categoryUrl : categoryUrls) {
//            if (categoryUrl.attr("href").startsWith("https")) {
//                // 处理分类
//                System.out.println("开始处理网址:" + categoryUrl.attr("href"));
////                dealCategoryPage(categoryUrl.attr("href"));
//                dealCategoryImage(imageMap, categoryUrl.attr("href"));
//                System.out.println("处理网址结束:" + categoryUrl.attr("href"));
//            }
//        }
//
//        System.out.println(JSONUtil.toJsonStr(imageMap));
//    }

//    public static void main(String[] args) {
//        ExcelReader reader = ExcelUtil.getReader("C:\\Users\\戴世坤\\Desktop\\新建文件夹\\新全产品数据.xls");
//        ExcelWriter writer2 = ExcelUtil.getWriter("C:\\Users\\戴世坤\\Desktop\\新建文件夹\\新全产品数据-修改后.xls");
//        List<Product> products = reader.readAll(Product.class);
//        List<Product> productResult = new ArrayList<>();
//        for (Product product : products) {
//            if ("variation".equals(product.getType())) {
//                product.setSKU(product.getSKU() + "-" + product.getAttribute1Value());
//            }
//            if (StrUtil.isNotBlank(product.getName())) {
//                productResult.add(product);
//            }
//        }
//        for (List<Product> productList : CollectionUtil.split(productResult, 100)) {
//            writer2.write(productList);
//            writer2.flush();
//        }
//        writer2.close();
//    }

    public static void dealCategoryPage(String url) {
        String s = HttpUtil.get(url);
        Document doc = Jsoup.parse(s);

        for (Element productE : doc.getElementsByClass("wd-entities-title")) {
            for (Element a : productE.getElementsByTag("a")) {
                String href = a.attr("href");
                executor.execute(() -> {
                    dealProduct(href);
                });
            }
        }
        // 处理完去第二页
        for (Element loop : doc.getElementsByClass("wd-loop-footer")) {
            for (Element a : loop.getElementsByTag("a")) {
                dealCategoryPage(a.attr("href"));
            }
        }
    }

    // 处理分类图片
    public static void dealCategoryImage(Map<String, String> imageMap, String url) {
        String s = HttpUtil.get(url);
        Document doc = Jsoup.parse(s);

        for (Element elementsByClass : doc.getElementsByClass("wrapp-category")) {
            String src = "";
            for (Element img : elementsByClass.getElementsByTag("img")) {
                src = img.attr("data-wood-src"); // 图片地址
            }
            String categoryName = "";
            for (Element byClass : elementsByClass.getElementsByClass("wd-entities-title")) {
                categoryName = byClass.ownText();
            }
            System.out.println(categoryName + "---" + src);
            if (StrUtil.isNotBlank(categoryName) && StrUtil.isNotBlank(src)) {
                imageMap.put(categoryName, src);
            }
        }

    }

}
